<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <title>Styles — Space.js</title>

    <link rel="preconnect" href="https://fonts.gstatic.com">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300&family=Gothic+A1:wght@400;700">
    <link rel="stylesheet" href="assets/css/style.css">

    <script type="module">
        import { Interface, shuffle, ticker } from '../src/index.js';

        class Config {
            static BREAKPOINT = 1000;
        }

        class Styles {
            static body = {
                fontFamily: 'Gothic A1, sans-serif',
                fontWeight: '400',
                fontSize: 13,
                lineHeight: '1.5',
                letterSpacing: 'normal'
            };

            static h1 = {
                width: 'fit-content',
                margin: '0 0 6px -1px',
                fontFamily: 'Roboto, sans-serif',
                fontWeight: '300',
                fontSize: 23,
                lineHeight: '1.3',
                letterSpacing: 'normal',
                textTransform: 'uppercase'
            };

            static content = {
                width: 'fit-content',
                margin: '6px 0',
                ...this.body
            };
        }

        class DetailsLink extends Interface {
            constructor(title, link) {
                super('.link', 'a');

                this.title = title;
                this.link = link;

                this.initHTML();

                this.addListeners();
            }

            initHTML() {
                this.css({
                    ...Styles.body,
                    lineHeight: 22
                });
                this.attr({ href: this.link });

                this.text = new Interface('.text');
                this.text.css({
                    display: 'inline-block'
                });
                this.text.text(this.title);
                this.add(this.text);

                this.line = new Interface('.line');
                this.line.css({
                    display: 'inline-block',
                    fontWeight: '700',
                    verticalAlign: 'middle'
                });
                this.line.html('&nbsp;&nbsp;―');
                this.add(this.line);
            }

            addListeners() {
                this.element.addEventListener('mouseenter', this.onHover);
                this.element.addEventListener('mouseleave', this.onHover);
            }

            // Event handlers

            onHover = ({ type }) => {
                this.line.tween({ x: type === 'mouseenter' ? 10 : 0 }, 200, 'easeOutCubic');
            };
        }

        class DetailsTitle extends Interface {
            constructor(title) {
                super('.title', 'h1');

                this.title = title;
                this.letters = [];

                this.initHTML();
                this.initText();
            }

            initHTML() {
                this.css({
                    ...Styles.h1
                });
            }

            initText() {
                const split = this.title.split('');

                split.forEach(str => {
                    if (str === ' ') {
                        str = '&nbsp';
                    }

                    const letter = new Interface(null, 'span');
                    letter.css({ display: 'inline-block' });
                    letter.html(str);
                    this.add(letter);

                    this.letters.push(letter);
                });
            }

            // Public methods

            animateIn = () => {
                shuffle(this.letters);

                const underscores = this.letters.filter(letter => letter === '_');

                underscores.forEach((letter, i) => {
                    letter.css({ opacity: 0 }).tween({ opacity: 1 }, 2000, 'easeOutCubic', i * 15);
                });

                const letters = this.letters.filter(letter => letter !== '_').slice(0, 2);

                letters.forEach((letter, i) => {
                    letter.css({ opacity: 0 }).tween({ opacity: 1 }, 2000, 'easeOutCubic', 100 + i * 15);
                });
            };
        }

        class Details extends Interface {
            constructor() {
                super('.details');

                this.texts = [];

                this.initHTML();
                this.initViews();

                this.addListeners();
                this.onResize();
            }

            initHTML() {
                this.invisible();
                this.css({
                    position: 'absolute',
                    left: 0,
                    top: 0,
                    width: '100%',
                    height: '100%',
                    display: 'flex',
                    alignItems: 'center',
                    pointerEvents: 'none',
                    opacity: 0
                });

                this.container = new Interface('.container');
                this.container.css({
                    width: 400,
                    margin: '10% 10% 13%'
                });
                this.add(this.container);
            }

            initViews() {
                this.title = new DetailsTitle('Lorem ipsum'.replace(/[\s.]+/g, '_'));
                this.title.css({
                    width: 'fit-content'
                });
                this.container.add(this.title);
                this.texts.push(this.title);

                this.text = new Interface('.text', 'p');
                this.text.css({
                    width: 'fit-content',
                    ...Styles.content
                });
                this.text.html('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.');
                this.container.add(this.text);
                this.texts.push(this.text);

                const items = [
                    {
                        title: 'Lorem ipsum',
                        link: 'https://en.wikipedia.org/wiki/Lorem_ipsum'
                    }
                ];

                items.forEach(data => {
                    const link = new DetailsLink(data.title, data.link);
                    link.css({
                        display: 'block',
                        width: 'fit-content'
                    });
                    this.container.add(link);
                    this.texts.push(link);
                });
            }

            addListeners() {
                window.addEventListener('resize', this.onResize);
            }

            // Event handlers

            onResize = () => {
                if (document.documentElement.clientWidth < Config.BREAKPOINT) {
                    this.css({ display: '' });

                    this.container.css({
                        width: '',
                        margin: '24px 20px 0'
                    });
                } else {
                    this.css({ display: 'flex' });

                    this.container.css({
                        width: 400,
                        margin: '10% 10% 13%'
                    });
                }
            };

            // Public methods

            animateIn = () => {
                this.visible();
                this.css({
                    pointerEvents: 'auto',
                    opacity: 1
                });

                const duration = 2000;
                const stagger = 175;

                this.texts.forEach((text, i) => {
                    const delay = i === 0 ? 0 : duration;

                    text.css({ opacity: 0 }).tween({ opacity: 1 }, duration, 'easeOutCubic', delay + i * stagger);
                });

                this.title.animateIn();
            };
        }

        class UI extends Interface {
            constructor() {
                super('.ui');

                this.initHTML();
                this.initViews();

                this.addListeners();
            }

            initHTML() {
                this.css({
                    position: 'fixed',
                    left: 0,
                    top: 0,
                    width: '100%',
                    height: '100%',
                    pointerEvents: 'none'
                });
            }

            initViews() {
                this.details = new Details();
                this.add(this.details);
            }

            addListeners() {
            }

            // Event handlers

            // Public methods

            animateIn = () => {
                this.details.animateIn();
            };
        }

        class App {
            static async init() {
                this.initViews();

                this.addListeners();
            }

            static initViews() {
                this.ui = new UI();
                document.body.appendChild(this.ui.element);
            }

            static addListeners() {
                window.addEventListener('load', this.onLoad);
                ticker.start();
            }

            // Event handlers

            static onLoad = () => {
                this.ui.animateIn();
            };
        }

        App.init();
    </script>
</head>
<body>
</body>
</html>
